#ifndef _BUOLA_GUI_CATTACHLAYOUTMANAGER_PRIVATE_H_
#define _BUOLA_GUI_CATTACHLAYOUTMANAGER_PRIVATE_H_

#include <buola/gui/cattachmanager.h>

#include <buola/gui/cwindow.h>

#include <buola/widgets/ctransparentresizebar.h>
#include <buola/widgets/chandlebar.h>
#include <buola/widgets/ctheme.h>

namespace buola { namespace gui {

////////////////////////////
/////// SRelocation ////////
////////////////////////////

struct CAttachManager::SRelocation
{
    //filled by SHandle
    CPoint_d mPoint;
    SPart *mRelocated;

    //filled by SPart
    SPart *mDestination;
    EAttachRelative mZone;
    CRect_d mRect;
    bool mTab;
};

/////////////////////////////
//////// SDecoration ////////
/////////////////////////////

class CAttachManager::SDecoration : public CWindow
{
public:
    SDecoration(SRoot *pRoot);
    ~SDecoration();

protected:
    int GetArea(const CPoint_d&);

////////////// Event handling //////////////
    virtual void OnSize(const CGeometryEvent &pE);
    virtual void OnExpose(const CExposeEvent &pE);
    virtual void OnButtonDown(const CMouseEvent &pE);
    virtual void OnButtonUp(const CMouseEvent &pE);
    virtual void OnMouseMove(const CMouseEvent &pE);
    virtual void OnMouseIn(const CMouseEvent &pE);
    virtual void OnMouseOut(const CMouseEvent &pE);

    void OnClose();
    void ShowClose(bool);

protected:
////////////////// data //////////////////
    SRoot *mRoot;
    int mPressedArea;
    CTheme::EDecoFlags mElements;
    bool mMouseIn;

////////////////// static data //////////////////
};

///////////////////////////////
//////// SResizeCorner ////////
///////////////////////////////

class CAttachManager::SResizeCorner : public CWindow
{
public:
    SResizeCorner(SRoot*);
    ~SResizeCorner();

protected:
////////////// Event handling //////////////
    void OnButtonDown(const CMouseEvent &pE);

protected:
////////////////// data //////////////////
    SRoot *mRoot;
};

//////////////////////
//////// STab ////////
//////////////////////

class CAttachManager::STab : public CWindow
{
    struct SItem
    {
        double mStart;
        double mWidth;
        std::wstring mTitle;
    };

public:
    STab(STabSplit *pSplit);
    ~STab();

protected:
    void DrawTab(img::CGC *pGC,double pX,double pW,const std::wstring &pText,bool pCur);

////////////// Event handling //////////////
    virtual void OnSize(const CGeometryEvent &pE);
    virtual void OnExpose(const CExposeEvent &pE);
    virtual void OnButtonDown(const CMouseEvent &pE);
    virtual void OnButtonUp(const CMouseEvent &pE);
    virtual void OnMouseMove(const CMouseEvent &pE);
    virtual void OnMouseOut(const CMouseEvent &pE);

protected:
////////////////// data //////////////////
    STabSplit *mSplit;
    std::vector<CRect_d> mRects;

////////////////// static data //////////////////
};

static const CSize_d cUndefinedSize(nUndefined);

///////////////////////
//////// SPart ////////
///////////////////////

struct CAttachManager::SPart
{
    SPart(CAttachManager *pManager);
    virtual ~SPart();

    EAttachRelative PlaceToRelative(EAttachPlace pPlace);
    EAttachRelative GetZone(const CPoint_d &pPos);
    CRect_d GetZoneRect(EAttachRelative pZone);
    virtual void FindRelocation(SRelocation&,bool pDescend=true);

    virtual void PlaceAttachment(SAttachment *pAttachment,EAttachPlace pPlace);
    virtual void AttachHere(SAttachment *pAttachment,EAttachRelative pPlace);
    virtual void Redraw()                       {                           }
    virtual void Reshape(const CRect_d &pR)       {   mRect=pR;mHidden=false; }
    virtual void ReshapeHidden()                {   mHidden=true;           }
    virtual bool IsVisible()                    {   return true;            }
    virtual EAttachFlags GetFlags()                   {   return ATTACH_NONE;            }
    virtual EAttachPlace GetDesiredPlace()            {   return ATTACH_ANY;            }
    virtual bool CanResizeH()                   {   return true;            }
    virtual bool CanResizeV()                   {   return true;            }
    virtual const CSize_d &GetDesiredSize()       {   return cUndefinedSize;  }
    virtual bool CanSave(SSaveHelper*)          {   return true;            }
    virtual std::wstring GetTitle()                 {   return std::wstring();  }
    virtual bool IsTabSplit()                   {   return false;           }
    virtual void ActivateChild(SPart*)          {}

    virtual void Save(xml::CNode pParent,SSaveHelper *pHelper)=0;

    CAttachManager *mManager;
    SSplit *mParent;
    CRect_d mRect;
    bool mHidden;
};

////////////////////////
//////// SSplit ////////
////////////////////////

struct CAttachManager::SSplit : public SPart
{
    SSplit(CAttachManager *pManager);
    ~SSplit();

    virtual void FindRelocation(SRelocation&,bool pDescend=true);

    virtual bool IsVisible();
    virtual void ReshapeHidden();

    void AddChild(SPart *pPart);
    void RemoveChild(SPart *pPart);
    void ReplaceChild(SPart *pPart,SPart *pWith);

    virtual void OnChildAdded(int)        {}
    virtual void OnChildRemoved(int)      {}
    virtual void OnChildReplaced(int)     {}

    void SaveChildren(xml::CNode pThis,SSaveHelper *pHelper);
    void LoadChildren(xml::CNode pThis,SSaveHelper *pHelper);

    std::vector<SPart*> mChildren;
};

//////////////////////////////
//////// SResizeSplit ////////
//////////////////////////////

struct CAttachManager::SResizeSplit : public SSplit
{
    SResizeSplit(CAttachManager *pManager);
    ~SResizeSplit();

    void SetPos(double pPerc,double pAbs);

    void PlaceResizeBar(const CRect_d&);
    void HideResizeBar();

    virtual void OnResizeBar(const CPoint_d&) {}

    virtual bool CanSave(SSaveHelper *pHelper);

    PTransparentResizeBar mBar;
    double mAbs;
    double mPerc;
    double mMax;
};

/////////////////////////
//////// SHSplit ////////
/////////////////////////

struct CAttachManager::SHSplit : public SResizeSplit
{
    SHSplit(CAttachManager *pManager,SPart *p1,SPart *p2);
    SHSplit(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    void PlaceAttachment(SAttachment *pAttachment,EAttachPlace pPlace);
    void Reshape(const CRect_d &pRect);
    void ReshapeHidden();
    void OnResizeBar(const CPoint_d &pPoint);

    bool CanResizeV();
    bool CanResizeH();

    void Save(xml::CNode pParent,SSaveHelper *pHelper);
};

/////////////////////////
//////// SVSplit ////////
/////////////////////////

struct CAttachManager::SVSplit : public SResizeSplit
{
    SVSplit(CAttachManager *pManager,SPart *p1,SPart *p2);
    SVSplit(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    void PlaceAttachment(SAttachment *pAttachment,EAttachPlace pPlace);
    void Reshape(const CRect_d &pRect);
    void ReshapeHidden();
    void OnResizeBar(const CPoint_d &pPoint);

    bool CanResizeV();
    bool CanResizeH();

    void Save(xml::CNode pParent,SSaveHelper *pHelper);
};

//////////////////////////////
//////// SScrollSplit ////////
//////////////////////////////

struct CAttachManager::SScrollSplit : public SSplit
{
    SScrollSplit(CAttachManager *pManager,SPart *pMain,
                                        SPart *pH,SPart *pV);
    SScrollSplit(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    void PlaceAttachment(SAttachment *pAttachment,EAttachPlace pPlace);
    void Reshape(const CRect_d &pRect);

    bool CanResizeH();
    bool CanResizeV();

    bool CanSave(SSaveHelper *pHelper);
    void Save(xml::CNode pParent,SSaveHelper *pHelper);
};

/////////////////////////
//////// SCSplit ////////
/////////////////////////

struct CAttachManager::SCSplit : public SSplit
{
    SCSplit(CAttachManager *pManager,SPart *p1,SPart *p2);
    SCSplit(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    void Reshape(const CRect_d &pRect);

    bool CanSave(SSaveHelper *pHelper);
    void Save(xml::CNode pParent,SSaveHelper *pHelper);
};

///////////////////////////
//////// STabSplit ////////
///////////////////////////

struct CAttachManager::STabSplit : public SSplit
{
    STabSplit(CAttachManager *pManager,SPart *p1,SPart *p2);
    STabSplit(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    virtual void AttachHere(SAttachment *pAttachment,EAttachRelative pPlace);
    virtual bool IsTabSplit()           {   return true;            }

    virtual void OnChildRemoved(int i);

    void Redraw();
    void Reshape(const CRect_d &pRect);
    void ReshapeHidden();
    void OnTab(int pWhich);
    virtual void ActivateChild(SPart *pChild);

    bool CanResizeV();
    bool CanResizeH();

    bool CanSave(SSaveHelper *pHelper);
    void Save(xml::CNode pParent,SSaveHelper *pHelper);

    int mCurrent;
    intrusive_ptr<STab> mTab;
};

///////////////////////
//////// SRoot ////////
///////////////////////

struct CAttachManager::SRoot : public SSplit
{
    SRoot(CAttachManager *pManager,SPart *pPart);
    SRoot(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    virtual void FindRelocation(SRelocation&,bool pDescend=true);

    void PlaceAttachment(SAttachment *pAttachment,EAttachPlace pPlace);
    void Reshape(const CRect_d &pRect);

    void Save(xml::CNode pParent,SSaveHelper *pHelper);

    void ShowDecoration(bool pShow);

    intrusive_ptr<SDecoration> mDecoration;
    intrusive_ptr<SResizeCorner> mResizeCorner;
};

/////////////////////////
//////// SClient ////////
/////////////////////////

struct CAttachManager::SClient : public SPart
{
    SClient(CAttachManager *pManager);
    SClient(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    void Save(xml::CNode pParent,SSaveHelper *pHelper);
};

/////////////////////////////
//////// SAttachment ////////
/////////////////////////////

struct CAttachManager::SAttachment : public SPart
{
    SAttachment(CAttachManager *pManager,const PWindow &pWindow,EAttachFlags pFlags,EAttachPlace pDesiredPlace);
    SAttachment(CAttachManager *pManager,xml::CNode pNode,SSaveHelper *pHelper);

    ~SAttachment();

    PWindow mWindow;
    EAttachFlags mFlags;
    CSize_d mDesiredSize;
    EAttachPlace mDesiredPlace;

    SRelocation mRelocation;

    PHandleBar mHandle;

    void DrawMark(const CRect_d &pRect,bool pMark);
    void UndrawMark(const CRect_d &pRect);
    void Redraw();
    void Reshape(const CRect_d &pRect);
    void ReshapeHidden();
    bool IsVisible();
    EAttachFlags GetFlags()               {   return mFlags;          }
    EAttachPlace GetDesiredPlace()        {   return mDesiredPlace;               }
    bool CanResizeH()               {   return mWindow->MinSize().Undefined()||mWindow->MinSize().x!=mWindow->MaxSize().x;    }
    bool CanResizeV()               {   return mWindow->MinSize().Undefined()||mWindow->MinSize().y!=mWindow->MaxSize().y;    }
    const CSize_d &GetDesiredSize()   {   return mDesiredSize;                }
    std::wstring GetTitle()             {   return L""; }///\todo something
    //!called by resizeattachby when a resize is requested externally
    void ResizeBy(const CSize_d &pInc);

    void PlaceHandle(const CRect_d &pRect);
    void HideHandle();

    bool CanSave(SSaveHelper *pHelper);
    void Save(xml::CNode pParent,SSaveHelper *pHelper);

    void OnStartMove(const CPoint_d &pPoint);
    void OnContinueMove(const CPoint_d &pPoint);
    void OnEndMove();
};

/*namespace gui*/ } /*namespace buola*/ }

#endif
